﻿using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using log4net;
using log4net.Config;
using System.Configuration;


namespace com.hyrentals.common
{
    public class Logger
    {
        private static bool _IsInit = false;
        private static string _ModuleName = string.Empty;
        private const string _LogFolderVarName = "LogDir";

        private static string GetLogModuleName()
        {
            string result = GetCallingModelName();

            string httpAppFullName = "System.Web.HttpApplication, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
            Type httpAppType = Type.GetType(httpAppFullName);
            if (httpAppType != null)
            {
                var appType = AppDomain.CurrentDomain.GetAssemblies()
                    .Where(x => !x.IsDynamic)
                    .SelectMany(x => x.GetExportedTypes())
                    .Select(x => x.BaseType)
                    .FirstOrDefault(x => x != null && x.IsSubclassOf(httpAppType));

                if (appType != null)
                {
                    result = Path.ChangeExtension(appType.Module.Name, null);
                }
            }

            return result;
        }

        private static string GetCallingModelName()
        {
            StackTrace st = new StackTrace(true);
            Type currentDeclaringType = MethodBase.GetCurrentMethod().DeclaringType;

            var frame = st.GetFrames()
                .Select(x => x.GetMethod().DeclaringType)
                .First(x => x != currentDeclaringType);

            return Path.ChangeExtension(frame.Module.Name, null);
        }

        public static void Reset(string ModelName)
        {
            _ModuleName = ModelName;
            _IsInit = false;
            Init();
        }

        private static ILog Init()
        {
            if (!_IsInit)
            {
                //Set Default Log folder
                if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(_LogFolderVarName))
                    || !Directory.Exists(Environment.GetEnvironmentVariable(_LogFolderVarName)))
                {
                    string sDefaultLogFolder = @"D:\data\log\";
                    string dataDir = ConfigurationManager.AppSettings["LogDir"];
                    if (!string.IsNullOrEmpty(dataDir) || Directory.Exists(dataDir))
                    {
                        sDefaultLogFolder = dataDir;
                    }
                    try
                    {
                        Directory.CreateDirectory(sDefaultLogFolder);
                        Environment.SetEnvironmentVariable(_LogFolderVarName, sDefaultLogFolder);
                    }
                    catch (Exception)
                    {
                        Environment.SetEnvironmentVariable(_LogFolderVarName, AppDomain.CurrentDomain.BaseDirectory);
                    }
                }

                if (string.IsNullOrEmpty(_ModuleName))
                {
                    _ModuleName = GetLogModuleName();
                }

                Environment.SetEnvironmentVariable("LogName", _ModuleName);
                _IsInit = true;
            }
            log4net.ILog log = log4net.LogManager.GetLogger(_ModuleName);
            return log;
        }

        public static ILog Init(string configFile)
        {
            ILog log = Init();
            XmlConfigurator.Configure(new FileInfo(configFile));

            return log;
        }

        public static ILog GetModelLogger(string modelName)
        {
            ILog defaultLog = Init();

            if (modelName == null ||
                modelName == _ModuleName)
            {
                return defaultLog;
            }

            return LogManager.GetLogger(modelName);
        }

        public static void Debug(object message)
        {
            Debug(message, null);
        }

        public static void Debug(object message, Exception e)
        {
            log4net.ILog log = Init();
            if (log.IsDebugEnabled)
            {
                log.Debug(message, e);
            }
            log = null;
        }

        public static void Error(object message)
        {
            Error(message, null);
        }
        public static void Error(object message, Exception e)
        {
            log4net.ILog log = Init();
            if (log.IsErrorEnabled)
            {
                log.Error(message, e);
            }
            log = null;
        }

        public static void Fatal(object message)
        {
            Fatal(message, null);
        }

        public static void Fatal(object message, Exception e)
        {
            log4net.ILog log = Init();
            if (log.IsFatalEnabled)
            {
                log.Fatal(message, e);
            }
            log = null;
        }

        public static void Info(object message)
        {
            Info(message, null);
        }

        public static void Info(object message, Exception e)
        {
            log4net.ILog log = Init();
            if (log.IsInfoEnabled)
            {
                log.Info(message, e);
            }
            log = null;
        }

        public static void Warn(object message)
        {
            Warn(message, null);
        }

        public static void Warn(object message, Exception e)
        {
            log4net.ILog log = Init();
            if (log.IsWarnEnabled)
            {
                log.Warn(message, e);
            }
            log = null;
        }

        public static void DealException(Exception e)
        {
            //TODO:
        }
    }
}
